package top.mable.interceptors;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import top.mable.annotation.EncryptDecryptClass;
import top.mable.annotation.EncryptDecryptField;
import top.mable.utils.AESUtil;

import java.lang.reflect.Field;
import java.sql.PreparedStatement;
import java.util.Objects;

/**
 *
 * 使用 ParameterHandler 对mybatis 的参数进行加密处理
 * @author taffywen
 * @date 2022/3/11 14:25
 */
@Slf4j
@Component
@Intercepts(@Signature(type = ParameterHandler.class,method = "setParameters",args = {PreparedStatement.class} ))
public class MyEncryptInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {

        log.info("进入MyEncryptInterceptor拦截器");
        if (invocation.getTarget() instanceof ParameterHandler){
            ParameterHandler parameterHandler = (ParameterHandler) invocation.getTarget();

            PreparedStatement ps = (PreparedStatement) invocation.getArgs()[0];

            //反射获取参数对象
            Field parameterField = parameterHandler.getClass().getDeclaredField("parameterObject");
            parameterField.setAccessible(true);
            Object parameterObject = parameterField.get(parameterHandler);
            if (Objects.nonNull(parameterObject)){
                Class<?> parameterClass = parameterObject.getClass();
                EncryptDecryptClass encryptDecryptClass  = AnnotationUtils.findAnnotation(parameterClass, EncryptDecryptClass.class);
                if (Objects.nonNull(encryptDecryptClass)){
                    Field[] declaredFields = parameterClass.getDeclaredFields();
                    for (Field field : declaredFields) {
                        if (field.isAnnotationPresent(EncryptDecryptField.class) && field.getType().toString().endsWith("String")){
                            field.setAccessible(true);
                            String fieldValue = (String) field.get(parameterObject);
                            if (StrUtil.isNotEmpty(fieldValue)){
                                field.set(parameterObject, AESUtil.encryptAES(fieldValue));
                            }
                            field.setAccessible(false);
                        }
                    }
                    
                }
            }
        }
        return invocation.proceed();
    }
}
